// src/components/editor.tsx
'use client';
import React, {FormEvent, MutableRefObject, RefObject, useEffect, useLayoutEffect, useRef, useState} from 'react';

import 'quill/dist/quill.snow.css'
import Quill, {QuillOptions} from "quill";
import {Button} from "@/components/ui/button";
import {PiTent, PiTextAa} from "react-icons/pi";
import {ImageIcon, Smile, XIcon} from "lucide-react";
import {MdSend} from "react-icons/md";
import Hint from "@/components/social/hint";
import {Delta, Op} from "quill/core";
import {cn} from "@/lib/utils";
import EmojiPopover from "@/components/social/emoji-popover";
import Image from "next/image";

type EditorValue = {
    image: File | null
    body: string
}

interface Props {
    variant?: 'create' | 'update'
    onSubmit: ({image, body}: EditorValue) => void
    onCancel?: () => void
    placeholder?: string
    defaultValue?: Delta | Op[]
    disabled?: boolean
    innerRef?: MutableRefObject<Quill | null>
    // imageElementRef : RefObject<HTMLInputElement>
    complete?: Function
}

const Editor = ({
                    complete,
                    variant = 'create', onCancel, onSubmit,
                    placeholder = 'Write something...',
                    defaultValue = [], innerRef,
                    disabled = false
                }: Props) => {
    const [text, setText] = useState('')
    // const [image, setImage] = useState<File | null>(null)
    const [image, setImage] = useState(null)
    const [isToolbarVisible, setIsToolbarVisible] = useState(true)

    // useRef 是一个 React Hook，它允许你引用渲染不需要的值。
    // effect里修改quill, 使用ref值不会触发effect
    const submitRef = useRef(onSubmit)
    const placeholderRef = useRef(placeholder)
    const quillRef = useRef<Quill | null>(null)
    const defaultValueRef = useRef(defaultValue)
    const disabledRef = useRef(disabled)
    const imageElementRef = useRef<HTMLInputElement>(null)

    const containerRef = useRef<HTMLDivElement>(null)

    useLayoutEffect(() => {
        submitRef.current = onSubmit
        placeholderRef.current = placeholder
        defaultValueRef.current = defaultValue
        disabledRef.current = disabled
    }, []);

    useEffect(() => {
        if (!containerRef.current) return

        const container = containerRef.current
        const editorContainer = container.appendChild(
            container.ownerDocument.createElement('div')
        )

        const options: QuillOptions = {
            theme: 'snow',
            placeholder: placeholderRef.current,
            modules: {
                toolbar: [
                    ['bold', 'italic', 'strike'],
                    ['link'],
                    [{list: 'ordered'}, {list: 'bullet'}]
                ],
                // enter改为发送, shift enter改为换行
                keyboard: {
                    bindings: {
                        enter: {
                            key: "Enter",
                            handler: () => {
                                const text = quill.getText()
                                const addedImage = imageElementRef.current?.files?.[0] || null

                                const isEmpty =
                                    !addedImage && text.replace(
                                        /<(.|\n)*?>/g, '').trim().length === 0

                                if (isEmpty) return

                                const body = JSON.stringify(quill.getContents())
                                submitRef.current?.({body, image: addedImage})
                            }
                        },
                        shift_enter: {
                            key: "Enter",
                            shiftKey: true,
                            handler: () => {
                                quill.insertText(quill.getSelection()?.index || 0, '\n')
                            }
                        },
                        shift_a:{
                            key:"A",
                            shiftKey: true,
                            handler:()=>{
                                complete?.(quill.getText())
                            }
                        }
                    }
                }
            }
        }

        const quill = new Quill(editorContainer, options)
        quillRef.current = quill
        quillRef.current.focus()

        if (innerRef) { // effect dependent
            innerRef.current = quill
        }

        quill.setContents(defaultValueRef.current)
        setText(quill.getText())

        quill.on(Quill.events.TEXT_CHANGE, () => {
            setText(quill.getText())
        })

        // 下次调用effect前执行
        return () => {
            quill.off(Quill.events.TEXT_CHANGE)
            if (container) {
                container.innerHTML = ''
            }
            if (quillRef.current) {
                quillRef.current = null
            }
            if (innerRef) {
                innerRef.current = null
            }
        }
    }, [innerRef]);

    const toggleToolbar = () => {
        setIsToolbarVisible((current) => !current)
        const toolbarElement = containerRef.current?.querySelector('.ql-toolbar')

        if (toolbarElement)
            toolbarElement.classList.toggle('hidden')
    }

    // 将<>和<>内的内容和换行 替换为空
    const isEmpty = !image && text.replace(/<(.|\n)*?>/g, '').trim().length === 0

    const onEmojiSelect = (emoji: any) => {
        const quill = quillRef.current

        // quill?.insertText(quill?.getSelection()?.index || 0, emoji.native)
        quill?.insertText(quill?.getSelection()?.index || 0, emoji)
    }

    // @ts-ignore
    const addImageToPost = (e) => {
        const reader = new FileReader()
        reader.onload = (readerEvent) => {
            // console.log(readerEvent.target.result)
            // @ts-ignore
            setImage(readerEvent.target.result) // image file 转base64
        }
        if (e.target.files[0]) {
            reader.readAsDataURL(e.target.files[0])
        } else {
            console.error('No file selected');
        }
    }

    return (
        <div className={`flex flex-col`}>
            <input
                accept={`image/*`}
                ref={imageElementRef}
                type="file"
                // onChange={(e) => setImage(e.target.files![0])}
                onChange={addImageToPost}
                className={`hidden`}
            />
            <div className={cn(
                `flex flex-col border border-slate-200 rounded-md overflow-hidden
            focus-within:border-slate-300 focus-within:shadow-sm transition bg-white`,
                disabled && `opacity-50`
            )}>
                <div ref={containerRef} className={`h-full ql-custom`}/>
                {/*!!转为boolean*/}
                {!!image && (
                    <div className={`p-2`}>
                        <div className={`relative size-[62px] flex items-center justify-center group/image`}>
                            <Hint label={`Remove image`}>
                                <button
                                    onClick={() => {
                                        setImage(null)
                                        imageElementRef.current!.value = ''
                                    }}
                                    className={`hidden group-hover/image:flex rounded-full bg-black/70 
                                hover:bg-black absolute -top-2.5 -right-2.5 text-white size-6
                                z-[4] border-2 border-white items-center justify-center`}
                                >
                                    <XIcon className={`size-3.5`}/>
                                </button>
                            </Hint>
                            <Image
                                // src={URL.createObjectURL(image)}
                                src={(image)}
                                alt={`Uploaded`}
                                fill
                                className={`rounded-xl`}
                            />
                        </div>
                    </div>
                )}
                <div className={`flex px-2 pb-2 z-[5]`}>
                    <Hint label={isToolbarVisible ? 'Hide formatting' : "Show formatting"}>
                        {/*format*/}
                        <Button
                            disabled={disabled}
                            size={'iconSm'}
                            variant={'ghost'}
                            onClick={toggleToolbar}
                        >
                            <PiTextAa className={`size-4`}/>
                        </Button>
                    </Hint>
                    <EmojiPopover
                        onEmojiSelected={onEmojiSelect}
                    >
                        {/*emoji*/}
                        <Button
                            disabled={disabled}
                            size={'iconSm'}
                            variant={'ghost'}
                        >
                            <Smile className={`size-4`}/>
                        </Button>
                    </EmojiPopover>
                    {variant === 'create' && (
                        <>
                            <Hint label={`Image`}>
                                {/*image*/}
                                <Button
                                    disabled={disabled}
                                    size={'iconSm'}
                                    variant={'ghost'}
                                    onClick={() => imageElementRef.current?.click()}
                                >
                                    <ImageIcon className={`size-4`}/>
                                </Button>
                            </Hint>
                            <Button
                                disabled={disabled || isEmpty}
                                onClick={() => {
                                    onSubmit({
                                        body: JSON.stringify(quillRef.current?.getContents()),
                                        image
                                    })
                                }}
                                size={'iconSm'}
                                className={cn(
                                    `ml-auto`,
                                    isEmpty
                                        ? `bg-white hover:bg-white text-muted-foreground`
                                        : `bg-[#007a5a] hover:bg-[#007a5a]/80 text-white`
                                )}
                            >
                                <MdSend className={`size-4`}/>
                            </Button>
                        </>
                    )}
                    {variant === 'update' && (
                        <div className={`ml-auto flex items-center gap-x-2`}>
                            <Button
                                size={'sm'}
                                onClick={() => {
                                    onSubmit({
                                        body: JSON.stringify(quillRef.current?.getContents()),
                                        image
                                    })
                                }}
                                className={`bg-[#007a5a] hover:bg-[#007a5a]/80 text-white`}
                                disabled={disabled || isEmpty}
                            >
                                Save
                            </Button>
                            <Button
                                disabled={disabled}
                                size={'sm'}
                                variant={'outline'}
                                onClick={onCancel}
                            >
                                Cancel
                            </Button>
                        </div>
                    )}
                </div>
            </div>
            {variant === 'create' && <div className={cn(
                `p-2 text-[10px] text-muted-foreground flex justify-end opacity-0 transition`,
                !isEmpty && `opacity-100`
            )}>
                <p>
                    <strong>Shift + Return</strong> to add a new line
                </p>
            </div>}
        </div>
    );
};

export default Editor